package cn.backpackerxl.easyJDBC.util;

import cn.backpackerxl.easyJDBC.annotation.ParesType;

import java.lang.reflect.Field;
import java.util.*;

public final class AddLongRule implements JSONParseRule {

    private boolean isArray;
    private boolean isList;
    private boolean isMap;


    @Override
    public boolean evaluate(JSONExpression jsonExpression) {
        boolean eval = false;
        this.isArray = jsonExpression.getField().getType().getTypeName().equals("java.lang.Long[]") || jsonExpression.getField().getType().getTypeName().equals("long[]");
        this.isList = jsonExpression.getTypeName().equals("java.util.List<java.lang.Long>");
        this.isMap = jsonExpression.getTypeName().equals("java.util.Map<java.lang.String, java.lang.Long>");
        if (jsonExpression.getTypeof() == Typeof.$LONG || jsonExpression.getTypeof() == Typeof.LONG || this.isArray || this.isList || this.isMap) {
            this.apply(jsonExpression.getObject(), jsonExpression.getField(), jsonExpression.getJsonObject());
            eval = true;
        }
        return eval;
    }

    private long getLone(Field field, JSONObject obj) {
        if (field.isAnnotationPresent(ParesType.class) && field.getDeclaredAnnotation(ParesType.class).value().equals(PType.INT)) {
            return Long.parseLong(String.valueOf(obj.getIntValue()));
        } else {
            return obj.getLongValue();
        }
    }

    @Override
    public void apply(Object entity, Field field, JSONObject obj) {
        try {
            if (this.isArray) {
                Object[] objects = obj.getArrays().stream().map(jsonObject -> this.getLone(field, jsonObject)).toArray();
                String ty = BasicUtil.typeName(field);
                Typeof typeof = MatchType.get(ty);
                switch (Objects.requireNonNull(typeof)) {
                    case LONG:
                        Long[] integers = Arrays.copyOf(objects, objects.length, Long[].class);
                        field.set(entity, integers);
                        break;
                    case $LONG:
                        long[] ints = new long[objects.length];
                        for (int i = 0; i < ints.length; i++) {
                            ints[i] = (long) objects[i];
                        }
                        field.set(entity, ints);
                        break;
                    default:
                        throw new RuntimeException("parse Long[] or long[] error.");
                }
            } else if (this.isList) {
                List<Long> list = new ArrayList<>();
                this.applyList(obj, field, list);
                field.set(entity, list);
            } else if (this.isMap) {
                Map<String, Long> map = new HashMap<>();
                this.applyMap(obj, field, map);
                field.set(entity, map);
            } else {
                field.set(entity, this.getLone(field, obj));
            }

        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    private void applyList(JSONObject obj, Field field, List<Long> list) {
        for (JSONObject jsonObject : obj.getArrays()) {
            list.add(this.getLone(field, jsonObject));
        }
    }

    private void applyMap(JSONObject obj, Field field, Map<String, Long> map) {
        for (JSONObject object : obj.getArrays()) {
            for (String s : object.getObjValue().keySet()) {
                map.put(s, this.getLone(field, object.getObjValue().get(s)));
            }
        }
    }
}
